use crate::abstract_unit::{logic::Logic, phisics::Physics, visual::Visual, unit::Animation, unit::Movement, unit::Unit};
use ggez::{glam::Vec2, graphics::{self, Color}, mint::Point2};
pub struct Predator {
    logic: Logic,
    physics: Physics,
    visual: Visual
}

impl Predator {
    pub fn new(logic: Logic, location: Vec2) -> Predator {
        let velocity = Vec2 { x: 0.0, y: 0.0 };
        let topspeed = logic.intelligence*100.0;
        let acceleration = Vec2 { x: 0.0, y: 0.0 };
        let linearsize = logic.luck*20.0;
        let mass = linearsize*linearsize*linearsize;
        let physics = Physics { location, velocity, topspeed, acceleration, mass, linearsize };

        let color = graphics::Color::new(logic.willpower, logic.luck, logic.intelligence, logic.coins);
        let size = linearsize;
        let visual = Visual { color, size };
        
        Predator { logic, physics, visual }
    }

    pub fn limit(&mut self) -> () {
        if self.physics.velocity.length() > self.physics.topspeed {self.physics.velocity = self.physics.topspeed*self.physics.velocity.normalize()}
    }
}

impl Animation for Predator {
    fn update(&mut self, ctx: &mut ggez::Context) -> () {
        self.physics.acceleration /= self.physics.mass;
        self.physics.velocity += self.physics.acceleration;
        self.limit();
        
        self.physics.location += self.physics.velocity;
        self.physics.acceleration *= 0.0;

        if (self.physics.location-Vec2{x: ctx.mouse.position().x, y: ctx.mouse.position().y}).length() < 20.0 { self.logic.coins += 0.001 }
        self.visual.color = graphics::Color::new(self.logic.willpower, self.logic.luck, self.logic.intelligence, self.logic.coins);

        self.physics.check_edges(ctx);
    }

    fn display(&self, ctx: &mut ggez::Context, canvas : &mut ggez::graphics::Canvas) -> () {
        let circle = graphics::Mesh::new_circle(
            ctx,
            graphics::DrawMode::fill(),
            Point2{x: self.physics.location.x, y: self.physics.location.y},
            self.visual.size,
            0.1,
            self.visual.color,
        ).unwrap();
        canvas.draw(&circle, graphics::DrawParam::default());

        let bcolor: Color;
        if self.logic.coins >= 1.0 {bcolor = graphics::Color::RED} else {bcolor = graphics::Color::BLACK}
        let circle = graphics::Mesh::new_circle(
            ctx,
            graphics::DrawMode::stroke(2.0),
            Point2{x: self.physics.location.x, y: self.physics.location.y},
            self.visual.size,
            0.1,
            bcolor,
        ).unwrap();
        canvas.draw(&circle, graphics::DrawParam::default());
    }
}

impl Movement for Predator {
    fn apply_force(&mut self, force: Vec2) -> () {
        if !force.is_nan() {self.physics.acceleration += force};
    }

    fn attract(& self, m: &Box<dyn crate::abstract_unit::unit::Unit>) -> Vec2 {
        let dirvector = self.physics.location - m.get_location();
        let mut distance = dirvector.length();
        distance = distance.clamp(5.0, 25.0);
        let g = 0.001;
        1.0*dirvector.normalize()* (g*self.physics.mass*m.get_mass())/(distance*distance)
    }

    fn get_location(& self) -> Vec2 {
        self.physics.location
    }

    fn get_mass(& self) -> f32 {
        self.physics.mass
    }

    fn get_velocity(& self) -> Vec2 {
        self.physics.velocity
    }

    fn get_intelligence(& self) -> f32 {
        self.logic.intelligence
    }

    fn get_luck(& self) -> f32 {
        self.logic.luck
    }

    fn get_willpower(& self) -> f32 {
        self.logic.willpower
    }

    fn get_coins(& self) -> f32 {
        self.logic.coins
    }
}

impl Unit for Predator {
    
}